<template>
  <div class="map-container">
    <div ref="mapContainerDom" class="map-container"></div>
    <!-- 重置定位控件 -->
    <div class="map-ctl" v-if="mapLoaded">
      <button
        v-show="mapLoaded"
        strong
        class="map-ctl-item"
        circle
        title="重置定位"
        @click="resetMap()"
      >
        
      </button>
    </div>
    <!-- 底图切换控件 -->
    <!-- <div class="base-map-ctl" v-if="mapLoaded">
      <div
        :class="showMapType === 'img' ? 'map-type-img map-type-img-selected' : 'map-type-img'"
        @click="changeMap('img')"
        title="卫星影像地图"
      >
        <img src="@/assets/image/map/img.png" />
      </div>
      <div
        :class="showMapType === 'vec' ? 'map-type-img map-type-img-selected' : 'map-type-img'"
        @click="changeMap('vec')"
        title="电子矢量地图"
      >
        <img src="@/assets/image/map/vec.png" />
      </div>
    </div> -->
    <!-- 标绘控制面板 -->
    <div class="draw-ctl" v-if="mapLoaded">
      <div class="draw-ctl-color">
        <p>边线颜色</p>
        <n-color-picker
          :default-value="featureStyleJSON.stroke.color"
          size="small"
          :modes="['hex']"
          :on-update:value="changeStrokeColor"
        />
        <p>填充颜色</p>
        <n-color-picker
          :default-value="featureStyleJSON.fill.color"
          size="small"
          :modes="['hex']"
          :on-update:value="changeFillColor"
        />
        <div class="draw-ctl-number-ctl">
          <p>边线宽度</p>
          <n-input-number
            v-model:value="featureStyleJSON.stroke.width"
            :min="1"
            :max="1000"
            clearable
            size="small"
          ></n-input-number>
        </div>
        <div class="draw-ctl-number-ctl">
          <p>点的半径</p>
          <n-input-number
            v-model:value="featureStyleJSON.image.radius"
            :min="1"
            :max="1000"
            clearable
            size="small"
          ></n-input-number>
        </div>
      </div>
      <div
        v-for="item in drawTypeList"
        :key="item.value"
        strong
        :class="item.activated ? 'draw-ctl-item draw-ctl-item-activate' : 'draw-ctl-item'"
        @click="activateDraw(item)"
      >
        {{ item.name }}
      </div>
      <div
        class="draw-ctl-item draw-ctl-item-save"
        :class="activateDel ? 'draw-ctl-item-save-activate' : ''"
        @click="delFeature()"
      >
        删除指定要素
      </div>
      <div class="draw-ctl-item draw-ctl-item-save" @click="clearDraw()">清空标绘</div>
      <div class="draw-ctl-item draw-ctl-item-save" @click="saveDraw()">保存标绘</div>
    </div>
    <!-- 删除区域提示文本 -->
    <div class="tool-tip" ref="toolTipDom">鼠标点击要删除的区域</div>
  </div>
</template>

<script lang="ts" setup>
import { OlUtil } from '../../lib/index'
import { onMounted, nextTick, ref, onBeforeUnmount, reactive } from 'vue'
import { Feature, Map } from 'ol'
import { get, Projection } from 'ol/proj'
import '../../lib/utils/ol-plot.css'
import { olPlot } from '../../lib/utils/olPlot'
import { DoubleClickZoom } from 'ol/interaction'
import VectorLayer from 'ol/layer/Vector'
import { Fill, Stroke, Style, Circle as CircleStyle } from 'ol/style'

const mapConfig = {
  defaultShowMap: 'img',
  imgMapType: 'WMTS',
  imgMapUrl: 'https://server.arcgisonline.com/arcgis/rest/services/World_Imagery/MapServer',
  vecMapType: 'XYZ',
  vecMapUrl: 'http://wprd04.is.autonavi.com/appmaptile?lang=zh_cn&size=1&style=7&x={x}&y={y}&z={z}',
  projectionCode: 'EPSG:3857',
  center: [81.8018641, 41.7792352],
  zoom: 15,
  maxZoom: 20,
  minZoom: 4,
  imgBaseUrl: ''
}

const olutil = new OlUtil()
let map: Map
const mapLoaded = ref(false)
let observer: ResizeObserver | null = null // 地图dom大小监听
const mapContainerDom = ref() // 地图容器

let mapProjection: Projection | undefined
const projectionCode = mapConfig.projectionCode || 'EPSG:3857'
if (projectionCode === 'EPSG:4490') {
  mapProjection = olutil.defineProjection_4490()
} else {
  mapProjection = get(projectionCode) as Projection
}
let ram: any
if (mapProjection) {
  ram = olutil.getResolutionsAndMids(mapProjection) // 获取分辨率和层级矩阵
}
const showMapType = ref(mapConfig.defaultShowMap) // 当前显示底图类型

// 标绘类型列表
const drawTypeList = ref([
  {
    name: '点',
    value: olPlot.PlotTypes.POINT,
    activated: false
  },
  {
    name: '线',
    value: olPlot.PlotTypes.POLYLINE,
    activated: false
  },
  {
    name: '多边形',
    value: olPlot.PlotTypes.POLYGON,
    activated: false
  },
  {
    name: '圆',
    value: olPlot.PlotTypes.CIRCLE,
    activated: false
  },
  {
    name: '矩形',
    value: olPlot.PlotTypes.RECTANGLE,
    activated: false
  },
  {
    name: '细直箭头',
    value: olPlot.PlotTypes.STRAIGHT_ARROW,
    activated: false
  },
  {
    name: '粗单直箭头',
    value: olPlot.PlotTypes.ASSAULT_DIRECTION,
    activated: false
  },
  {
    name: '粗单尖头箭头',
    value: olPlot.PlotTypes.FINE_ARROW,
    activated: false
  },
  {
    name: '集结地',
    value: olPlot.PlotTypes.GATHERING_PLACE,
    activated: false
  },
  {
    name: '进攻方向',
    value: olPlot.PlotTypes.ATTACK_ARROW,
    activated: false
  },
  {
    name: '双箭头',
    value: olPlot.PlotTypes.DOUBLE_ARROW,
    activated: false
  },
  {
    name: '文本框',
    value: olPlot.PlotTypes.TEXTAREA,
    activated: false
  }
])
let plot: olPlot
let drawState: string // 当前绘制状态
// 标绘单独设置要素的样式
const featureStyleJSON = reactive({
  stroke: {
    color: '#f00',
    width: 2
  },
  fill: {
    color: '#ffb10061'
  },
  image: {
    radius: 10,
    fill: {
      color: '#f00'
    }
  }
})
// 标绘默认样式
const drawDefaultStyle = new Style({
  stroke: new Stroke({
    color: featureStyleJSON.stroke.color,
    width: featureStyleJSON.stroke.width
  }),
  fill: new Fill({
    color: featureStyleJSON.fill.color
  }),
  image: new CircleStyle({
    radius: featureStyleJSON.image.radius,
    fill: new Fill({
      color: featureStyleJSON.image.fill.color
    })
  })
})

let saveFeaturesStr: any // 保存的标绘数据的字符串
const activateDel = ref(false) // 是否激活删除功能
const toolTipDom = ref() // 提示文本dom

// 修改边线颜色
const changeStrokeColor = (val: string) => {
  featureStyleJSON.stroke.color = val
}
// 修改填充颜色
const changeFillColor = (val: string) => {
  featureStyleJSON.fill.color = val
  featureStyleJSON.image.fill.color = val
}
// 加载地图
const loadMap = (id: string, mapUrl: string, type: string) => {
  let layer
  if (type === 'XYZ') {
    layer = olutil.loadXYZLayer({
      id,
      url: mapUrl,
      projection: mapConfig.projectionCode
    })
  } else if (type === 'WMTS') {
    layer = olutil.loadWMTSLayer({
      id,
      url: mapUrl,
      matrixSet: 'default028mm',
      projection: mapProjection,
      resolutions: ram.resolutions,
      matrixIds: ram.matrixIds
    })
  }
  layer && layer.setVisible(mapConfig.defaultShowMap === id)
  return layer
}
// 初始化地图
const initMap = () => {
  const vecMapLayer = loadMap('vec', mapConfig.vecMapUrl, mapConfig.vecMapType)
  const imgMapLAyer = loadMap('img', mapConfig.imgMapUrl, mapConfig.imgMapType)

  map = olutil.initMap(mapContainerDom.value, {
    center: mapConfig.center || [87.62, 43.83],
    zoom: mapConfig.zoom || 8,
    minZoom: mapConfig.minZoom || 6,
    maxZoom: mapConfig.maxZoom || 18,
    layers: [imgMapLAyer!, vecMapLayer!]
  })
  // 移除所有双击缩放交互
  map
    .getInteractions()
    .getArray()
    .forEach((interaction) => {
      if (interaction instanceof DoubleClickZoom) {
        map.removeInteraction(interaction)
      }
    })
}

// 重置地图
const resetMap = () => {
  const center = mapConfig.center || [81.8018641, 41.7792352]
  const zoom = mapConfig.zoom || 8
  const duration = 500
  olutil.setCenterAndZoom({ center, zoom, duration })
}

// 切换底图
const changeMap = (id: string) => {
  if (showMapType.value === id) {
    return
  }
  // 隐藏旧底图
  const lastedMap = olutil.getLayer(showMapType.value)
  lastedMap && lastedMap.setVisible(false)
  // 显示选中底图
  const nowMap = olutil.getLayer(id)
  nowMap && nowMap.setVisible(true)
  // 记录选中底图
  showMapType.value = id
}

// 获取标绘图层

const getDrawLayer = (id: string) => {
  if (!map) return
  return map
    .getLayers()
    .getArray()
    .find(function (layer) {
      const layerId = layer.get('layerName')
      return layerId && layerId === id
    })
}
// 初始化标绘
const initDraw = () => {
  plot = new olPlot(map, {
    layerName: 'drawLayer'
  })

  // 获取标绘图层
  const drawLayer = getDrawLayer('drawLayer') as VectorLayer
  console.log(drawLayer, '---drawLayer')
  // 设置标绘图层样式
  drawLayer.setStyle(drawDefaultStyle)
  registerDrawEvent()
}

// 激活标绘
const activateDraw = (sitem: any) => {
  activateDel.value = false // 取消删除功能
  // 按钮状态设置为未激活
  drawTypeList.value.forEach((item: any) => {
    item.activated = false
  })
  // 激活当前选中按钮
  sitem.activated = true
  const type = sitem.value
  if (!plot) return
  plot.plotEdit.deactivate()
  plot.plotDraw.activate(type)
}

// 保存标绘
const saveDraw = () => {
  clearDrawEvent()
  if (!plot) return
  updateDraw()
  // window.$dialog.warning({
  //   title: '提示',
  //   content: '确定保存标绘？',
  //   positiveText: '确定',
  //   negativeText: '取消',
  //   onPositiveClick: () => {
  //     // 调用接口保存数据
  //     updateDraw(() => {window.$message.success('保存成功！')})
  //   },
  //   onNegativeClick: () => {
  //     window.$message.error('取消保存！')
  //   }
  // })
}

// 接口更新保存数据
const updateDraw = (callback?: any) => {
  if (!plot) return
  const features = plot.plotUtils.getFeatures() // 序列化地图上所有符号
  saveFeaturesStr = JSON.stringify(features)
  // 此次调用保存接口
  callback && callback()
}

// 载入保存
const loadDraw = () => {
  if (!plot) return
  if (!saveFeaturesStr) return
  plot.plotUtils.removeAllFeatures() // 清除地图上所有符号
  const features = JSON.parse(saveFeaturesStr)
  plot.plotUtils.addFeatures(features) // 反序列化地图上所有符号
}

// 清除标绘相关事件
const clearDrawEvent = () => {
  activateDel.value = false // 取消删除功能
  if (plot) {
    plot.plotDraw.deactivate() // 取消绘制功能
    plot.plotEdit.deactivate() // 取消编辑功能
  }
  // 按钮状态设置为未激活
  drawTypeList.value.forEach((item: any) => {
    item.activated = false
  })
}

// 清空标绘
const clearDraw = () => {
  clearDrawEvent()
  if (!plot) return
  // window.$dialog.warning({
  //   title: '提示',
  //   content: '确定清空标绘？',
  //   positiveText: '确定',
  //   negativeText: '取消',
  //   onPositiveClick: () => {
  //     plot.plotUtils.removeAllFeatures() // 清除地图上所有符号
  //     saveFeaturesStr = null
  //     // 调用接口保存数据
  //     window.$message.success('清空成功！')
  //   },
  //   onNegativeClick: () => {
  //     window.$message.error('取消清空！')
  //   }
  // })
}

// 删除指定要素
const delFeature = () => {
  clearDrawEvent()
  activateDel.value = !activateDel.value
}

// 注册标绘事件
const registerDrawEvent = () => {
  if (!plot) return

  plot.plotDraw.on('drawStart' as any, (evt: any) => {
    console.log('---drawStart')
    console.log(evt, '---evt')
    drawState = evt.type
    const featureStyle = new Style({
      stroke: new Stroke({
        color: featureStyleJSON.stroke.color,
        width: featureStyleJSON.stroke.width
      }),
      fill: new Fill({
        color: featureStyleJSON.fill.color
      }),
      image: new CircleStyle({
        radius: featureStyleJSON.image.radius,
        fill: new Fill({
          color: featureStyleJSON.image.fill.color
        })
      })
    })
    // 自定义样式
    evt.feature && evt.feature.setStyle(featureStyle)
  })
  plot.plotDraw.on('drawEnd' as any, (evt: any) => {
    drawState = evt.type
    console.log('---drawEnd')
    console.log(evt, '---evt')
    // 按钮状态设置为未激活
    drawTypeList.value.forEach((item: any) => {
      item.activated = false
    })
  })
}

let selectedFeature: Feature | null = null
// 设置feature的边框颜色
const setFeatureStrokeColor = (feature: Feature, color?: string) => {
  if (feature) {
    let style = feature.getStyle()
    if (style) {
      style = (style as Style).clone()
    } else {
      style = new Style({
        stroke: new Stroke({
          color: color || featureStyleJSON.stroke.color,
          width: featureStyleJSON.stroke.width
        }),
        fill: new Fill({
          color: featureStyleJSON.fill.color
        }),
        image: new CircleStyle({
          radius: featureStyleJSON.image.radius,
          fill: new Fill({
            color: featureStyleJSON.image.fill.color
          })
        })
      })
    }
    const stroke = style.getStroke()
    if (stroke) {
      stroke.setColor(color || featureStyleJSON.stroke.color)
      style.setStroke(stroke)
    }
    feature.setStyle(style)
  }
}
// 注册地图事件
const registerMapEvent = () => {
  if (!map) return
  const offsetX = 20
  const offsetY = -5
  map.on('click', (e) => {
    const result = map.forEachFeatureAtPixel(e.pixel, (feature: any, layer: any) => {
      return { feature, layer }
    })
    // 判断是否是标绘创建的要素
    if (result && result.feature && result.feature.get('isPlot')) {
      // 点击选中要删除的区域
      if (activateDel.value) {
        // 还原上一个选中的区域的样式
        if (selectedFeature) {
          setFeatureStrokeColor(selectedFeature)
          selectedFeature = null
        }
        // 设置当前选中区域的样式
        selectedFeature = result.feature
        selectedFeature && setFeatureStrokeColor(selectedFeature, 'blue')
        // 弹出提示文本
        // window.$dialog.warning({
        //   title: '提示',
        //   content: '确定删除该区域？',
        //   positiveText: '确定',
        //   negativeText: '取消',
        //   onPositiveClick: () => {
        //     // 删除选中的区域
        //     result.layer.getSource().removeFeature(selectedFeature)
        //     // 关闭提示文本
        //     activateDel.value = false
        //     // 保存数据
        //     updateDraw(() => window.$message.success('删除成功！'))
        //   },
        //   onNegativeClick: () => {
        //     // 关闭删除按钮激活状态
        //     activateDel.value = false
        //     // 还原选中的区域的样式
        //     if (selectedFeature) {
        //       setFeatureStrokeColor(selectedFeature)
        //       selectedFeature = null
        //     }
        //     window.$message.error('取消删除！')
        //   }
        // })
      } else {
        // 进入编辑状态
        if (plot && plot.plotEdit && (drawState === 'drawEnd' || drawState === 'edit')) {
          plot.plotEdit.activate(result.feature)
          drawState = 'edit'
        }
      }
    } else {
      // 取消编辑状态
      if (plot && plot.plotEdit) {
        plot.plotEdit.deactivate()
        drawState = 'drawEnd'
      }
    }
  })

  // 鼠标移动事件
  map.on('pointermove', (e: any) => {
    // 删除提示文本
    if (activateDel.value && toolTipDom.value) {
      const x = e.pixel[0]
      const y = e.pixel[1]
      toolTipDom.value.style.display = 'block'
      toolTipDom.value.style.left = `${x + offsetX}px`
      toolTipDom.value.style.top = `${y + offsetY}px`
    } else {
      if (toolTipDom.value) {
        toolTipDom.value.style.display = 'none'
      }
    }
  })
}
onMounted(() => {
  initMap()
  nextTick(() => {
    map &&
      map.once('rendercomplete', () => {
        mapLoaded.value = true
        // 监听地图dom大小变化
        observer = new ResizeObserver(() => {
          map && map.updateSize()
        })
        observer.observe(mapContainerDom.value)
        registerMapEvent()
        initDraw()
      })
  })
})
defineExpose({})
onBeforeUnmount(() => {
  try {
    observer && observer.unobserve(mapContainerDom.value) // 移除监听
  } catch (err) {
    console.log(err)
  }
})
</script>
<script lang="ts">
export default {
  name: 'DrawMap'
}
</script>
<style lang="scss" scoped>
.map-container {
  position: absolute;
  width: 100%;
  height: 100%;
  overflow: hidden;
  .base-map-ctl {
    position: absolute;
    right: 0.2rem;
    bottom: 0.1rem;
    display: flex;
    background: rgba(31, 30, 30, 0.5);
    box-shadow: 2px 2px rgba(0, 0, 0, 0.4);
    border-radius: 3px;
    padding: 0.1rem;
    .map-type-img {
      height: 60px;
      width: 86px;
      cursor: pointer;
      border: 2px solid transparent;
    }

    .map-type-img-selected {
      border: 2px solid #2d8cf0;
    }
    .map-type-img:last-child {
      margin-left: 0.05rem;
    }
  }
  .map-ctl {
    position: absolute;
    left: 0.2rem;
    top: 0.2rem;
    display: flex;
    flex-direction: column;
    background: rgba(0, 0, 0, 0.5);
    padding: 0.1rem 0.08rem;
    border-radius: 4px;
    .map-ctl-item {
      margin-bottom: 0.1rem;
    }
    .map-ctl-item:last-child {
      margin-bottom: 0;
    }
  }
  .draw-ctl {
    position: absolute;
    right: 0.2rem;
    top: 0.2rem;
    display: flex;
    flex-direction: column;
    background: rgba(0, 0, 0, 0.5);
    padding: 0.1rem 0.08rem;
    border-radius: 4px;
    .draw-ctl-color {
      margin-bottom: 0.1rem;
      p {
        text-align: center;
        color: white;
        margin-bottom: 0.05rem;
      }
      .draw-ctl-number-ctl {
        display: flex;
        margin-bottom: 0.1rem;
        justify-content: center;
        align-items: center;
        p {
          margin-bottom: 0;
        }
        .n-input-number {
          flex: 1;
          padding-left: 0.1rem;
          width: 100px;
        }
      }
    }
    .draw-ctl-item {
      color: white;
      text-align: center;
      padding: 0.02rem 0.1rem;
      border: 1px solid #2d8cf0;
      border-radius: 4px;
      background: #035bb9;
      cursor: pointer;
      user-select: none;
      width: 120px;
      margin-left: auto;
      margin-right: auto;
      margin-bottom: 0.1rem;
    }
    .draw-ctl-item:hover {
      background: #2d8cf0;
      border: 1px solid #2d8cf0;
      color: white;
    }
    .draw-ctl-item-activate {
      background: #2d8cf0;
      border: 1px solid #2d8cf0;
      color: white;
    }
    .draw-ctl-item:last-child {
      margin-bottom: 0;
    }
    .draw-ctl-item-save {
      background: #061f9f;
      border: 1px solid #2d8cf0;
      color: white;
    }
    .draw-ctl-item-save:hover {
      background: #042bec;
    }
    .draw-ctl-item-save-activate {
      background: #042bec;
    }
  }
  .tool-tip {
    border: 1px solid #2d8cf0;
    color: black;
    background: rgba(255, 255, 255, 0.8);
    padding: 0 4px;
    border-radius: 5px;
    position: absolute;
    box-shadow: 4px 4px 2px rgba(0, 0, 0, 0.4);
    left: -150%;
    top: -150%;
    display: none;
  }
}
</style>
